package com.itheima.filter;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;

import com.itheima.util.AppJwtUtil;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * @author Hakuna Matata
 * @date 2022-09-23-9:31
 */
@Component
@Order(-1)
public class AuthFilter implements GlobalFilter {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 1.获取请求参数
        ServerHttpRequest request = exchange.getRequest();
        //登录和验证验证码的请求不要进行token校验, 直接放行, 因为没有token
        //request.getPath();
        //public interface ServerHttpRequest extends HttpRequest, ReactiveHttpInputMessage {
        //    RequestPath getPath();
        String path = request.getURI().getPath();
        //   URI的   public String getPath() {
        //要放行的uri  获去验证码和校验验证码的uri
        String[] URIs = {
                "/admin/login", //登录
                "/admin/logout", //登出
                "/admin/register", //注册
                "/admin/refreshToken" // 刷新token, 不确定是否要加入
        };
        //匹配
        for (String uris : URIs) {
            if (StrUtil.equals(uris, path)) {
                //放行
                return chain.filter(exchange);
                //Mono<Void> filter(ServerWebExchange exchange);
            }
        }

        // 2.获取authorization参数
        //取出来第一个匹配的
        String token = request.getHeaders().getFirst("Authorization");

        // 3.校验token
        //token校验
        if (StrUtil.isNotBlank(token)) {
            token = token.replace("Bearer ", "");
            Claims claimsBody = AppJwtUtil.getClaimsBody(token);//工具类要用之前的, 因为c部分加密的盐值要用同一个
            //校验是否过期
            int i = AppJwtUtil.verifyToken(claimsBody);
            //@return -1：有效，0：有效，1：过期，2：过期
            if (i == -1 || i == 0) {
                //将token里的用户id放进threadLocal里  --> 不行了, 因为和app不在同一个模块, 不是同一个线程
                //用户id放进redis里, 后续其他功能和模块会使用
                Object id = claimsBody.get("id");
                String key = "AUTH_USER_ID";
                stringRedisTemplate.opsForValue().set(key, Convert.toStr(id));
                //本来是设计了过期时间, 但是考虑到每个请求都会来一次网关的过滤器走一趟, 又自动存进redis里token和id了
                //而且后续的用户登录也是将此key和值进行覆盖换成自己的id值
                //所以也就不用考虑过期时间了
                //long time = claimsBody.getExpiration().getTime();

                //放行
                return chain.filter(exchange);
            }
        }


        // 4.拦截  没有登录的
        // 4.1.没有权限 设置状态码  401
        exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);

        return exchange.getResponse().setComplete();

    }

}
